	
	;; asmx, SNASM68K, and asm68k create byte perfect versions

VDPAddress:	equ	$00C00000
WordRAMStart:	equ	$00200000
	
	;; shortcuts for args linked
Arg00Link:	equ	$8
Arg02Link:	equ	Arg00Link+$02
Arg04Link:	equ	Arg00Link+$04
Arg06Link:	equ	Arg00Link+$06
Arg08Link:	equ	Arg00Link+$08
Arg0CLink:	equ	Arg00Link+$0C

MainPlayStart:	
	;; to start Cinepak, JSR to to this location
	BRA	CinepakStart
Ticks:	
	dc.l	$00000000
	dc.w	$0000,$0000,$0000,$0000

	dc.w	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
	dc.w	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
	dc.w	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
	dc.w	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000

	dc.w	$0000,$0000
HeapStart:	
	;; never set, wonder if Main heap (which does not exist) or Sub heap
	dc.l	$00000000
HeapSize:	
	dc.l	$00000000
PrintY:	
	dc.l	$00000000
PrintX:	
	dc.l	$00000000
	dc.w	$0000,$0000,$0000,$0000,$0000,$0000

	dc.w	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
	dc.w	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000


CinepakStart:
	;; FX args$00.l: saved to CinepakVintUserCall
	;;    (0 means no call, nonzero means jsr to this address)
	LEA      CinepakVintUserCall(PC),A0
	MOVE.L   $4(A7),(A0)
	;; save original vint
	LEA      OriginalVint(PC),A0
	MOVE.L   ($FFFFFD08).W,(A0)
	;; save SR, turn off all interrupts, set new vint, restore SR
	LEA      CinepakVint(PC),A0
	MOVE     SR,D0
	ORI      #$2700,SR
	MOVE.L   A0,($FFFFFD08).W
	MOVE     D0,SR
	;; TODO not sure why checking this word in the communication command
	;; checking for $13 in communication command and will set to second
	;; tile set index
	MOVEA.L  #$A12000,A5
	CMPI.W   #$13,$1E(A5)
	BEQ.S    CinepakStartSetFrameTileSetIndexToOne
	BRA.S    CinepakStartLeaveFrameTileSetIndexAlone
CinepakStartSetFrameTileSetIndexToOne:	
	LEA      FrameTileSetIndex(PC),A0
	MOVE.W   #$1,(A0)
CinepakStartLeaveFrameTileSetIndexAlone:	
	JSR      MAINCODE(PC)
CinepakStartWaitForPendingFrame:
	MOVE.W   NewFrameReady(PC),D0
	BNE.S    CinepakStartWaitForPendingFrame
	;; save SR, turn off all interrupts, restore original vint, restore SR
	MOVEA.L  OriginalVint(PC),A0
	MOVE     SR,D0
	ORI      #$2700,SR
	MOVE.L   A0,($FFFFFD08).W
	MOVE     D0,SR
	RTS

OriginalVint:
	dc.l	$00000000
CinepakVintUserCall:	
	dc.l	$00000000

	;; unused subroutine
ClearAndSetupVDPWithMainFont:	
	MOVEA.L  #VDPAddress,A0
	;; set VDP increment to 2
	MOVE.W   #$8F02,4(A0)
	;; setup VRAM write for VRAM address $0000
	MOVEQ    #$0000,D0
	LSL.L    #2,D0
	LSR.W    #2,D0
	BSET     #14,D0
	SWAP     D0
	MOVE.L   D0,4(A0)
	MOVEQ    #$0,D0
	;; clear all of VRAM
	MOVE.L   #$3FFF,D1
ClearVRAMLoop:	
	MOVE.L   D0,(A0)
	DBF      D1,ClearVRAMLoop
	MOVEQ    #$0,D0
	;; setup CRAM write
	;; set to all black palette except second color is white
	MOVE.L   #$C0000000,4(A0)
	MOVE.L   #$EEE,(A0)
	MOVE.L   D0,(A0)
	MOVE.L   D0,(A0)
	MOVE.L   D0,(A0)
	MOVE.L   D0,(A0)
	MOVE.L   D0,(A0)
	MOVE.L   D0,(A0)
	MOVE.L   D0,(A0)
	MOVE.W   #$9001,$4(A0)
	MOVE.W   #$8B00,$4(A0)
	BSR.S    MainFontSetup
	MOVE.W   #$8238,$4(A0)
	MOVE.W   #$857C,$4(A0)
	MOVE.W   #$8D3F,$4(A0)
	RTS
	;; end unused subroutine
	
	;; subroutine only called by unused subroutine
MainFontSetup:	
	;; set VDP increment to 2
	MOVE.W   #$8F02,4(A0)
	;; setup VRAM write for VRAM address $0000
	MOVEQ    #$0,D0
	LSL.L    #2,D0
	LSR.W    #2,D0
	BSET     #14,D0
	SWAP     D0
	MOVE.L   D0,4(A0)
	;; clear VRAM $0000-$0400
	MOVEQ    #$0,D1
	MOVE.W   #$FF,D0
VRAM0000To04000Clear:	
	MOVE.L   D1,(A0)
	DBF      D0,VRAM0000To04000Clear
	LEA      MainFont(PC),A1
	MOVE.W   #$2FF,D3
	;; main font is compressed to 1 bit per pixel
	;; need to expand to 4 bits per pixel for VDP
MainFontCopy:	
	;; decompress one byte into long word
	MOVE.B   (A1)+,D0
	MOVEQ    #$7,D2
MainFontCopyDecompressByteLoop:	
	LSL.L    #4,D1
	;; multiply by 2 and check carry out
	ADD.B    D0,D0
	BCS.S    MainFontCopyPixelOne
	ORI.B    #2,D1
	DBF      D2,MainFontCopyDecompressByteLoop
	BRA.S    MainFontCopyDecompressByteDone
MainFontCopyPixelOne:	
	ORI.B    #1,D1
	DBF      D2,MainFontCopyDecompressByteLoop
MainFontCopyDecompressByteDone:	
	MOVE.L   D1,(A0)
	DBF      D3,MainFontCopy
	RTS
	;; end subroutine only called by unused subroutine

CinepakVint:	
	MOVEM.L  D0-D7/A0-A5,-(A7)
	;; sends vint signal to sub
	MOVEA.L  #$A12000,A0
	BSET     #0,(A0)
	;; only copy frame data if NewFrameReady
	LEA      NewFrameReady(PC),A2
	TST.W    (A2)
	BEQ      CinepakVintSkipFrameCopy
	MOVEA.L  #VDPAddress,A0
	LEA      Palettes(PC),A1
	;; setup CRAM write
	MOVE.L   #$C0000000,4(A0)
	MOVE.W   NumberOfPalettesMinus1(PC),D0
CinepakVintPaletteCopy:	
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	DBF      D0,CinepakVintPaletteCopy
	;; clear NewFrameReady
	CLR.W    (A2)
	MOVE.L   FrameTileMapVRAMStart(PC),D3
	LEA      FrameTileMap(PC),A2
	MOVE.L   FrameTileMapOffsetBetweenRows(PC),D2
	MOVE.L   FrameTileHeight(PC),D7
	;; prepare tile height for dbf by subtracting one
	SUBQ.W   #1,D7
	MOVE.L   FrameTileWidth(PC),D6
	MOVEQ    #$7,D0
	AND.W    D6,D0
	BNE.S    TileMapCopySlow

	;; FrameTileWidth is on 8 tile boundary, faster copy
	;; divide tile width by 8
	LSR.W    #3,D6
	;; prepare tile width for dbf by subtracting one
	SUBQ.W   #1,D6
TileMapCopyFastRow:	
	;; copy dbf counter so can save original
	MOVE.W   D6,D5
	;; setup VRAM write address
	;; and increment VRAM plain address to next row address
	MOVE.L   D3,D0
	ADD.L    D2,D3
	LSL.L    #2,D0
	LSR.W    #2,D0
	BSET     #14,D0
	SWAP     D0
	MOVE.L   D0,4(A0)
TileMapCopyFastNextEightTiles:	
	MOVE.L   (A2)+,(A0)
	MOVE.L   (A2)+,(A0)
	MOVE.L   (A2)+,(A0)
	MOVE.L   (A2)+,(A0)
	DBF      D5,TileMapCopyFastNextEightTiles
	DBF      D7,TileMapCopyFastRow
	BRA.S    TileMapCopyDone

TileMapCopySlow:	
	;; prepare tile width for dbf by subtracting one
	SUBQ.W   #1,D6
TileMapCopySlowRow:
	;; copy dbf counter so can save original
	MOVE.W   D6,D5
	;; setup VRAM write address
	;; and increment VRAM plain address to next row address
	MOVE.L   D3,D0
	ADD.L    D2,D3
	LSL.L    #2,D0
	LSR.W    #2,D0
	BSET     #14,D0
	SWAP     D0
	MOVE.L   D0,4(A0)
TileMapCopySlowNextTile:	
	MOVE.W   (A2)+,(A0)
	DBF      D5,TileMapCopySlowNextTile
	DBF      D7,TileMapCopySlowRow

TileMapCopyDone:	
	LEA      FrameTileSetIndex(PC),A2
	EORI.W   #$1,(A2)
CinepakVintSkipFrameCopy:	
	;; increment Ticks
	LEA      Ticks(PC),A0
	ADDQ.L   #1,(A0)

	MOVE.L   CinepakVintUserCall(PC),D0
	BEQ.S    CinepakVintSkipUserCall
	MOVEA.L  D0,A0
	JSR      (A0)
CinepakVintSkipUserCall:	
	MOVEM.L  (A7)+,D0-D7/A0-A5
	RTE

NewFrameReady:	
	dc.w	$0000
FrameTileSetIndex:	
	dc.w	$0000
NumberOfPalettesMinus1:	
	dc.w	$0000
	;; unused word
	dc.w	$0000
Palettes:	
	;; can have up to four palettes
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
FrameTileMapVRAMStart:	
	dc.l	$E000
FrameTileMapOffsetBetweenRows:	
	dc.l	64*2
FrameTileWidth:	
	dc.l	$00000000
FrameTileHeight:	
	dc.l	$00000010
FrameTileMap:	
	;; $0A00 or $1000 bytes
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
	dc.w	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

	
	;; FX args$00.l: print y location
	;; FX args$04.l: print x location
	;; FX args$08.l: string to print
drawprintSub:	
	LINK     A6,#$0
	MOVEM.L  D0-D7/A0-A5,-(A7)
	MOVEA.L  #VDPAddress,A0
	;; start VRAM address
	MOVEA.L  #$E000,A2
	MOVE.L   Arg04Link(A6),D0
	;; multiply by 2
	ADD.L    D0,D0
	ADDA.L   D0,A2
	MOVE.L   Arg00Link(A6),D0
	MULU.W   #(64*2),D0
	ADDA.L   D0,A2
	;; set VDP increment to 2
	MOVE.W   #$8F02,4(A0)
	;; setup VRAM write
	MOVE.L   A2,D0
	LSL.L    #2,D0
	LSR.W    #2,D0
	BSET     #14,D0
	SWAP     D0
	MOVE.L   D0,4(A0)
	MOVEQ    #$0,D0
	MOVEA.L  Arg08Link(A6),A1
drawprintSubCopyCharactersToVDP:	
	MOVE.B   (A1)+,D0
	;; check for null character (string terminator)
	BEQ.S    drawprintSubEndOfString
	MOVE.W   D0,(A0)
	BRA.S    drawprintSubCopyCharactersToVDP
drawprintSubEndOfString:	
	MOVEM.L  (A7)+,D0-D7/A0-A5
	UNLK     A6
	;; get return address, pop arguments off stack, and return from sub
	MOVEA.L  (A7)+,A0
	LEA      $C(A7),A7
	JMP      (A0)

	;; unused subroutine
	;; wait until zero NewFrameReady
SetBlackFrame:	
SetBlackFrameWaitForPendingFrame:	
	MOVE.W   NewFrameReady(PC),D0
	BNE.S    SetBlackFrameWaitForPendingFrame
	MOVEA.L  #VDPAddress,A0
	;; setup VRAM write to E000
	MOVE.L   #$E000,D0
	LSL.L    #2,D0
	LSR.W    #2,D0
	BSET     #14,D0
	SWAP     D0
	MOVE.L   D0,4(A0)
	;; clear tile map $1000 bytes
	MOVEQ    #$0,D0
	MOVE.W   #$3FF,D1
SetBlackFrameClearTileMap:	
	MOVE.L   D0,(A0)
	DBF      D1,SetBlackFrameClearTileMap
	;; set to second frame tile set
	LEA      FrameTileSetIndex(PC),A0
	MOVE.W   #$1,(A0)
	;; set to all black palette except second color is white
	LEA      Palettes(PC),A0
	MOVE.L   #$EEE,(A0)+
	CLR.L    (A0)+
	CLR.L    (A0)+
	CLR.L    (A0)+
	CLR.L    (A0)+
	CLR.L    (A0)+
	CLR.L    (A0)+
	CLR.L    (A0)+
	;; set frame waiting for vint to draw frame
	LEA      NewFrameReady(PC),A0
	MOVE.W   #$1,(A0)
SetBlackFrameWaitForPendingFrameAgain:	
	MOVE.W   (A0),D0
	BNE.S    SetBlackFrameWaitForPendingFrameAgain
	MOVEQ    #$0,D0
	RTS
	;; end unused subroutine

DrawFrame:	
	;; FX args$00.l: third long word in word RAM (tile priority)
	;; FX args$04.l: second long word in word RAM (VRAM map start)
	;; FX args$08.l: first long word in word RAM (VRAM tile offset)
	;; FX args$0C.l: word RAM start
	LINK     A6,#$0
	MOVEM.L  D0-D7/A0-A5,-(A7)
	;; wait until zero NewFrameReady
	LEA      NewFrameReady(PC),A2
DrawFrameWaitForPendingFrame:	
	TST.W    (A2)
	BNE.S    DrawFrameWaitForPendingFrame
	;; VDP address
	MOVEA.L  #VDPAddress,A0
	MOVEA.L  Arg08Link(A6),A4
	LEA      FrameTileMapVRAMStart(PC),A1
	MOVE.L   Arg04Link(A6),(A1)
	;; get frame data start address
	MOVEA.L  Arg0CLink(A6),A1
	;; check for SM in first two bytes
	CMPI.W   #'SM',(A1)
	BNE      DrawFrameEnd
	;; tile width
	MOVE.W   $8(A1),D6
	;; tile height
	MOVE.W   $A(A1),D7
	;; set a5 to zero
	SUBA.L   A5,A5
	MOVE.W   FrameTileSetIndex(PC),D1
	BNE.S    DrawFrameFrameTileSetSetupDone
	;; using second tile set, need to determine offsets
	MOVEQ    #$0,D0
	;; save tile width * tile height in a5 (since a5 already zero)
	;; add tile width * tile height * 32 in a4
	MOVE.W   D6,D0
	MULU.W   D7,D0
	ADDA.L   D0,A5
	LSL.L    #5,D0
	ADDA.L   D0,A4
DrawFrameFrameTileSetSetupDone:	
	;; get palette count
	MOVE.W   $2(A1),D1
	ANDI.W   #$3,D1
	LEA      NumberOfPalettesMinus1(PC),A2
	MOVE.W   D1,(A2)
	MOVE.W   D1,D0
	;; get palette start
	LEA      $C(A1),A1
	LEA      Palettes(PC),A2
DrawFramePaletteCopy:	
	MOVE.L   (A1)+,(A2)+
	;; set first color of each palette to $000
	CLR.W    -$4(A2)
	MOVE.L   (A1)+,(A2)+
	MOVE.L   (A1)+,(A2)+
	MOVE.L   (A1)+,(A2)+
	MOVE.L   (A1)+,(A2)+
	MOVE.L   (A1)+,(A2)+
	MOVE.L   (A1)+,(A2)+
	MOVE.L   (A1)+,(A2)+
	DBF      D0,DrawFramePaletteCopy

	LEA      FrameTileWidth(PC),A3
	MOVE.L   D6,(A3)
	LEA      FrameTileHeight(PC),A3
	MOVE.L   D7,(A3)

	LEA      FrameTileMap(PC),A3
	MOVE.L   D7,-(A7)
	;; determine tile offset
	MOVE.L   Arg08Link(A6),D3
	LSR.L    #5,D3
	ADD.W    A5,D3
	;; determine tile priority
	MOVE.L   Arg00Link(A6),D0
	BEQ.S    DrawFrameFinishSettingTilePriority
	;; set high priority for tiles
	BSET     #15,D3
DrawFrameFinishSettingTilePriority:	
	MOVEQ    #$1,D2
	MOVE.W   D7,D5
	BRA.S    DrawFramePaletteRowCopyLoopCondition
DrawFramePaletteRowCopyLoop:	
	MOVE.W   D6,D4
	BRA.S    DrawFramePaletteTileCopyLoopCondition
DrawFramePaletteTileCopyLoop:	
	SUBQ.W   #1,D2
	BNE.S    DrawFrameHavePaletteInformation
	;; BUG, single palette SUB does not add this information
	MOVE.L   (A1)+,D7
	MOVEQ    #$11,D1
	ROR.L    D1,D7
	MOVEQ    #$10,D2
DrawFrameHavePaletteInformation:	
	MOVE.W   D7,D1
	ROL.L    #2,D7
	ANDI.W   #$6000,D1
	ADD.W    D3,D1
	ADDQ.W   #1,D3
	MOVE.W   D1,(A3)+
DrawFramePaletteTileCopyLoopCondition:	
	DBF      D4,DrawFramePaletteTileCopyLoop
DrawFramePaletteRowCopyLoopCondition:	
	DBF      D5,DrawFramePaletteRowCopyLoop

	MOVE.L   (A7)+,D7
	MOVEQ    #$0,D2
	MOVE.W   D6,D2
	MULU.W   D7,D2
	LSL.L    #4,D2
	MOVE.L   A4,D0
	BSR.S    DrawFrameTileDMACopy
	BRA.S    DrawFrameEnd

	;; unused code
	MOVE.L   A4,D0
	LSL.L    #2,D0
	LSR.W    #2,D0
	BSET     #14,D0
	SWAP     D0
	MOVE.L   D0,4(A0)
	BRA.S    DrawFrameTileDataRowCopyLoopCondition
DrawFrameTileDataRowCopyLoop:	
	MOVE.W   D6,D4
	BRA.S    DrawFrameTileDataTileCopyLoopCondition
DrawFrameTileDataTileCopyLoop:	
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
	MOVE.L   (A1)+,(A0)
DrawFrameTileDataTileCopyLoopCondition:	
	DBF      D4,DrawFrameTileDataTileCopyLoop
DrawFrameTileDataRowCopyLoopCondition:	
	DBF      D7,DrawFrameTileDataRowCopyLoop
	;; end of unused code
	
DrawFrameEnd:	
	;; set NewFrameReady
	LEA      NewFrameReady(PC),A2
	MOVE.W   #$1,(A2)
	MOVEM.L  (A7)+,D0-D7/A0-A5
	UNLK     A6
	MOVEA.L  (A7)+,A0
	LEA      $10(A7),A7
	JMP      (A0)

	;; FX arg d0.l DMA VRAM destination address
	;; FX arg d2.w DMA word length
	;; FX arg a1.l DMA 68k source address
DrawFrameTileDMACopy:	
	;; copy half the tiles
	LSR.L    #1,D2
	MOVEM.L  D0-D2/A0-A1,-(A7)
	BSR      DrawFrameTileDMACopyHalf
	NOP
	NOP
	NOP
	NOP
	MOVEM.L  (A7)+,D0-D2/A0-A1
	;; determine second half tiles address starts by adding byte count
	;; note d2 is a word count so need to multiply by 2 and restore later
	LSL.L    #1,D2
	ADDA.L   D2,A1
	ADD.L    D2,D0
	LSR.L    #1,D2
	BSR      DrawFrameTileDMACopyHalf
	RTS

	;; FX arg d0.l DMA VRAM destination address
	;; FX arg d2.w DMA word length
	;; FX arg a1.l DMA 68k source address
DrawFrameTileDMACopyHalf:	
	;; skip first long word (will copy later)
	MOVE.L   A1,D1
	ADDQ.W   #2,D1
	LSR.L    #1,D1
	;; set VDP increment to 2
	MOVE.W   #$8F02,4(A0)
	;; set display enable, vblank ints, dma enable, NTSC, genesis mode
	MOVE.W   #$8174,4(A0)
	;; set DMA length low
	MOVE.W   #$9300,D3
	MOVE.B   D2,D3
	MOVE.W   D3,4(A0)
	;; set DMA length high
	LSR.W    #8,D2
	MOVE.W   #$9400,D3
	MOVE.B   D2,D3
	MOVE.W   D3,4(A0)
	;; set DMA source address low
	MOVE.W   #$9500,D3
	MOVE.B   D1,D3
	MOVE.W   D3,4(A0)
	;; set DMA source address mid
	LSR.L    #8,D1
	MOVE.W   #$9600,D3
	MOVE.B   D1,D3
	MOVE.W   D3,4(A0)
	;; set DMA source address high (and 68k to VRAM copy)
	LSR.W    #8,D1
	MOVE.W   #$9700,D3
	MOVE.B   D1,D3
	MOVE.W   D3,4(A0)
	;; determine VRAM address to start VRAM DMA copy
	LSL.L    #2,D0
	LSR.W    #2,D0
	SWAP     D0
	ORI.L    #$40000080,D0
	MOVE.L   D0,4(A0)
	;; disable DMA now
	MOVE.W   #$8164,4(A0)
	;; set VRAM write to same address as start VRAM DMA copy
	ANDI.W   #$FF7F,D0
	MOVE.L   D0,4(A0)
	;; copy first long word now
	MOVE.L   (A1),(A0)
	RTS

MainFont:	
	incbin	MAINFONT.BIN

DoDrawTextCommand:	
	LINK     A6,#-$100
	MOVEM.L  D6-D7/A4,-(A7)
	LEA      -$100(A6),A4
	CLR.W    D6
	BRA.S    DoDrawTextCommandGetCommand
DoDrawTextCommandPerform:	
	CMPI.B   #$1,D7
	BNE.S    DoDrawTextCommandAddText
	MOVE.W   D6,D0
	ADDQ.W   #1,D6
	CLR.B    $0(A4,D0.W)
	BRA.S    DoDrawTextCommandEnd
DoDrawTextCommandAddText:	
	MOVE.W   D6,D0
	ADDQ.W   #1,D6
	MOVE.B   D7,$0(A4,D0.W)
DoDrawTextCommandGetCommand:	
	;; get command and check that it is non-zero
	JSR      GetCommandFromSub(PC)
	MOVE.B   D0,D7
	BNE.S    DoDrawTextCommandPerform
DoDrawTextCommandEnd:	
	;; push text address, call aprint, and pop
	MOVE.L   A4,-(A7)
	JSR      aprint(PC)
	ADDQ.W   #4,A7
	MOVEM.L  -$10C(A6),D6-D7/A4
	UNLK     A6
	RTS

	dc.b	$91,"DoDrawTextCommand",$00,$00
	even

DoMoviePlayBack:	
	LINK     A6,#$0
	MOVEM.L  D5-D7/A4,-(A7)
	;; word RAM start
	MOVEA.L  #WordRAMStart,A4
	;; VRAMTileDataStart
	MOVE.L   (A4),D5
	;; VRAMTileMapStart with offsets for FilmX and FilmY
	MOVE.L   $4(A4),D6
	;; FilmTilePriority
	MOVE.L   $8(A4),D7
	BRA.S    DoMoviePlayBackCheckCommand
	;; Set1MFlag to 1
DoMoviePlayBackPerform:	
	MOVEQ    #$1,D0
	MOVE.L   D0,-(A7)
	JSR      Set1MFlag(PC)
	;; set args to DrawFrame, call DrawFrame (and DrawFrame pops the args)
	MOVE.L   #WordRAMStart,-(A7)
	MOVE.L   D5,-(A7)
	MOVE.L   D6,-(A7)
	MOVE.L   D7,-(A7)
	JSR      DrawFrame(PC)
	;; Set1MFlag to 0
	MOVEQ    #$0,D0
	MOVE.L   D0,-(A7)
	JSR      Set1MFlag(PC)
	;; pop args from two Set1MFlag calls
	ADDQ.W   #8,A7
DoMoviePlayBackCheckCommand:	
	;; check if command is $2
	JSR      GetCommandFromSub(PC)
	CMPI.W   #$2,D0
	BEQ.S    DoMoviePlayBackPerform
	MOVEM.L  -$10(A6),D5-D7/A4
	UNLK     A6
	RTS

	dc.b	$8F,"DoMoviePlayBack",$00,$00
	even
	
MAINCODE:
	LINK     A6,#$0
	MOVE.L   D7,-(A7)
	JSR      InitWorld(PC)
	;; push string, call aprint, pop
	PEA      StringMAINCPUReadyToHandleCommand(PC)
	JSR      aprint(PC)
	ADDQ.W   #4,A7
	BRA.S    MAINCODEGetCommandFromSub
MAINCODEPerformCommand:	
	MOVE.W   D7,D0
	;; command $01 draw text
	SUBQ.W   #1,D0
	BEQ.S    MAINCODEDoDrawTextCommand
	;; command $03 start movie playback
	SUBQ.W   #2,D0
	BEQ.S    MAINCODEDoMoviePlayBack
	BRA.S    MAINCODEUnknownCommand
MAINCODEDoDrawTextCommand:	
	JSR      DoDrawTextCommand(PC)
	BRA.S    MAINCODEGetCommandFromSub
MAINCODEDoMoviePlayBack:	
	JSR      DoMoviePlayBack(PC)
	BRA.S    MAINCODEEnd
MAINCODEUnknownCommand:	
	EXT.L    D7
	MOVE.L   D7,-(A7)
	PEA      StringCommandNumStr(PC)
	JSR      aprint(PC)
	ADDQ.W   #8,A7
MAINCODEGetCommandFromSub:	
	JSR      GetCommandFromSub(PC)
	MOVE.W   D0,D7
	BNE.S    MAINCODEPerformCommand
MAINCODEEnd:	
	;; push string, call aprint, pop
	PEA      StringMainDone(PC)
	JSR      aprint(PC)
	ADDQ.W   #4,A7
	MOVE.L   -$4(A6),D7
	UNLK     A6
	RTS

	dc.b	$88,"MAINCODE",$00
	dc.b	$00
	dc.b	$38
StringMainDone:	
	dc.b	"Main Done",$00
StringCommandNumStr:	
	dc.b	"Command: %d",$00
StringMAINCPUReadyToHandleCommand:	
	dc.b	"MAINCPU ready to handle commands"
	even
	dc.b	$00,$00
	even
	
Redraw:	
	LINK     A6,#$0
	UNLK     A6
	RTS

	dc.b	$86,"ReDraw",$00,$00,$00
	even

	;; FX args$00.l: string to print with newline
DrawText:
drawprint:	
	LINK     A6,#$0
	MOVE.L   Arg00Link(A6),-(A7)
	LEA      MainPlayStart(PC),A0
	;; pass PrintX
	MOVE.L   $5C(A0),-(A7)
	LEA      MainPlayStart(PC),A0
	;; pass PrintY
	MOVE.L   $60(A0),-(A7)
	JSR      drawprintSub(PC)
	LEA      MainPlayStart(PC),A0
	;; increment PrintY
	ADDQ.L   #1,$60(A0)
	LEA      MainPlayStart(PC),A0
	MOVEQ    #24,D0
	CMP.L    $60(A0),D0
	;; branch if PrintY < 24
	BGT.S    drawprintHasMoreRows
	LEA      MainPlayStart(PC),A0
	;; decrement PrintY by 20 (so go back to 4 in typical case)
	SUBI.L   #20,$60(A0)
drawprintHasMoreRows:	
	JSR      Redraw(PC)
	UNLK     A6
	RTS

	dc.b	$89,"drawprint",$00,$00
	even
	
	include	NUMSTR.ASM

	include	HEXSTR.ASM

	;; has macro include for macro if
aprint:
	LINK     A6,#-$128
	MOVEM.L  D4-D7/A3-A4,-(A7)
	;; start of scratch space
	LEA      -$128(A6),A4
	;; makes aprint do nothing... real useful...
	BRA	 aprintBypass
aprintParseFormatStringLoop:	
	CMPI.B   #'%',D6
	BEQ.S    aprintHandleFormatTag
	;; normal character, copy to output
	MOVE.B   D6,(A3)+
	BRA      aprintGetNextFormatStringCharacter
aprintHandleFormatTag:	
	MOVEQ    #$8,D4
	MOVEA.L  Arg00Link(A6),A0
	ADDQ.L   #1,Arg00Link(A6)
	MOVE.B   (A0),D6
	MOVE.B   D6,D0
	;; check for %* (means width is not specified but as an extra arg)
	SUBI.B   #'*',D0
	BNE.S    aprintFormatTagWithNoArgumentWidth
	ADDQ.L   #4,-$4(A6)
	MOVEA.L  -$4(A6),A0
	MOVE.W   -$2(A0),D4
	MOVE.L   Arg00Link(A6),D0
	ADDQ.L   #1,Arg00Link(A6)
	MOVEA.L  D0,A0
	MOVE.B   (A0),D6
aprintFormatTagWithNoArgumentWidth:	
	MOVE.B   D6,D0
	;; %%
	SUBI.B   #'%',D0
	BEQ      aprintDoublePercentCharacter
	;; %S
	SUBI.B   #$2E,D0
	BEQ.S    aprintString
	;; %X
	SUBQ.B   #5,D0
	BEQ.S    aprintUnsignedHexadecimalInteger
	;; %d
	SUBI.B   #$C,D0
	BEQ.S    aprintSignedDecimalInteger
	;; %s
	SUBI.B   #$F,D0
	BEQ.S    aprintString
	;; %x
	SUBQ.B   #5,D0
	BEQ.S    aprintUnsignedHexadecimalInteger
	;; unsupported format tag, ignore and process next character
	BRA      aprintGetNextFormatStringCharacter
aprintSignedDecimalInteger:	
	ADDQ.L   #4,-$4(A6)
	MOVEA.L  -$4(A6),A0
	MOVE.L   -$4(A0),D5
	MOVE.L   A4,-(A7)
	EXT.L    D4
	MOVE.L   D4,-(A7)
	MOVE.L   D5,-(A7)
	JSR      NumStr(PC)
	CLR.W    D7
	LEA      $C(A7),A7
	BRA.S    Label1534
Label152C:	
	MOVE.B   $0(A4,D7.W),(A3)+
	MOVE.W   D7,D0
	ADDQ.W   #1,D7
Label1534:	
	TST.B    $0(A4,D7.W)
	BNE.S    Label152C
	BRA.S    aprintGetNextFormatStringCharacter
aprintUnsignedHexadecimalInteger:	
	ADDQ.L   #4,-$4(A6)
	MOVEA.L  -$4(A6),A0
	MOVE.L   -$4(A0),D5
	MOVE.L   A4,-(A7)
	EXT.L    D4
	MOVE.L   D4,-(A7)
	MOVE.L   D5,-(A7)
	JSR      HexStr(PC)
	CLR.W    D7
	LEA      $C(A7),A7
	BRA.S    Label1564
Label155C:	
	MOVE.B   $0(A4,D7.W),(A3)+
	MOVE.W   D7,D0
	ADDQ.W   #1,D7
Label1564:	
	TST.B    $0(A4,D7.W)
	BNE.S    Label155C
	BRA.S    aprintGetNextFormatStringCharacter
aprintString:
	ADDQ.L   #4,-$4(A6)
	MOVEA.L  -$4(A6),A0
	MOVE.L   -$4(A0),-$8(A6)
	BRA.S    Label1588
Label157C:	
	MOVE.L   -$8(A6),D0
	ADDQ.L   #1,-$8(A6)
	MOVEA.L  D0,A0
	MOVE.B   (A0),(A3)+
Label1588:	
	MOVEA.L  -$8(A6),A0
	;; check for null character (string terminator)
	TST.B    (A0)
	BNE.S    Label157C
	BRA.S    aprintGetNextFormatStringCharacter
aprintDoublePercentCharacter:	
	;; normal character, copy to output
	MOVE.B   D6,(A3)+
aprintGetNextFormatStringCharacter:	
	MOVE.L   Arg00Link(A6),D0
	ADDQ.L   #1,Arg00Link(A6)
	MOVEA.L  D0,A0
	MOVE.B   (A0),D6
	;; check for null character (string terminator)
	BNE      aprintParseFormatStringLoop
	CLR.B    (A3)+
	PEA      -$108(A6)
	JSR      DrawText(PC)
	ADDQ.W   #4,A7
aprintBypass:	
	MOVEM.L  -$140(A6),D4-D7/A3-A4
	UNLK     A6
	RTS

	dc.b	$86,"aprint",$00,$00,$00
	even
	

InitWorld:
	LINK     A6,#$0
	;; clear command
	MOVEA.L  #$A12010,A0
	CLR.W    (A0)
	;; clear 1M flag
	MOVEA.L  #$A12010,A0
	CLR.W    $2(A0)
	LEA      MainPlayStart(PC),A0
	MOVEQ    #4,D0
	;; set PrintX to 4
	MOVE.L   D0,$5C(A0)
	LEA      MainPlayStart(PC),A0
	;; set PrintY to 4
	MOVE.L   D0,$60(A0)

	PEA     StringMAINCPUIsAlive(PC)
	JSR      aprint(PC)
	LEA      MainPlayStart(PC),A0
	;; HeapStart
	MOVE.L   $54(A0),-(A7)
	PEA      StringHeapStartHexNum(PC)
	JSR      aprint(PC)
	LEA      MainPlayStart(PC),A0
	;; HeapSize
	MOVE.L   $58(A0),-(A7)
	PEA      StringHeapSizeHexNum(PC)
	JSR      aprint(PC)
	
	UNLK     A6
	RTS

	dc.b	$89,"InitWorld"
	dc.b	$00
	dc.b	$32
StringHeapSizeHexNum:	
	dc.b	"Heap Size : %x",$00,$00
StringHeapStartHexNum:	
	dc.b	"Heap Start: %x",$00,$00
StringMAINCPUIsAlive:	
	dc.b	"MAINCPU is alive"
	dc.b	$00,$00
	even
	
GetCommandFromSub:	
	;; FX returns:d0.w non-zero command sent by sub
	LINK     A6,#$0
	MOVEM.L  D7/A3-A4,-(A7)
	MOVEA.L  #$A12010,A3
	MOVEA.L  #$A12020,A4
	;; get command from sub and save in d7
GetCommandFromSubWaitNonZero:	
	MOVE.W   (A4),D7
	BEQ.S    GetCommandFromSubWaitNonZero
	;; send one to acknowledge command received
	MOVE.W   #$1,(A3)
	;; get zero command from sub to finish handshake
GetCommandFromSubWaitZero:
	TST.W    (A4)
	BNE.S    GetCommandFromSubWaitZero
	;; send zero to acknowledge command received
	CLR.W    (A3)
	MOVE.W   D7,D0
	MOVEM.L  -$C(A6),D7/A3-A4
	UNLK     A6
	RTS

	dc.b	$91,"GetCommandFromSub",$00,$00
	even
	
Set1MFlag:	
	;; FX args$00.w: upper word is ignored
	;; FX args$02.w: lower word is sent
	LINK     A6,#$0
	MOVEA.L  #$A12010,A0
	MOVE.W   Arg02Link(A6),$2(A0)
	UNLK     A6
	RTS

	dc.b	$89,"Set1MFlag",$00,$00
	even
	include	DIVIDE.ASM
